Spring 扩展点之FactoryBean

前言

Spring框架为开发者提供了很多可扩展的点,FactoryBean接口就是其中一个,常用于返回包装之后的Bean对象,例如实现指定注解的动态代理功能等。

接口定义

public interface FactoryBean<T> {

/**
* 当调用getBean时,底层调用此方法,获取包装之后的Bean对象
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* <p>As with a {@link BeanFactory}, this allows support for both the
* Singleton and Prototype design pattern.
* @throws Exception in case of creation errors
* @see FactoryBeanNotInitializedException
*/
T getObject() throws Exception;

/**
* 当调用applicationContext.getBean(xxx.class),IOC容器进行类型匹配。
* @return the type of object that this FactoryBean creates,
* or {@code null} if not known at the time of the call
* @see ListableBeanFactory#getBeansOfType
*/
Class<?> getObjectType();

/**
* 当前Bean是否是单例
* Is the object managed by this factory a singleton? That is,
* will {@link #getObject()} always return the same object
* (a reference that can be cached)?
* {@code isSingleton()} implementation returns {@code false}.
* @return whether the exposed object is a singleton
* @see #getObject()
* @see SmartFactoryBean#isPrototype()
*/
boolean isSingleton();

}

自定义扩展实现

本案例只是模拟Spring的动态代理功能,但是Spring并不是扩展FactoryBean接口实现的,而是扩展BeanPostProcessor接口实现,关于这个后续会讲到,不是本篇的重点。

public static class ProxyFactoryBean<T> implements FactoryBean<T> {

// 被代理的类className
private String proxyClassName;

public void setProxyClassName(String proxyClassName) {
this.proxyClassName = proxyClassName;
}

// 返回代理类
public T getObject() throws Exception {
Class innerClass = Class.forName(proxyClassName);
// 如果是接口则返回JDK动态代理
if(innerClass.isInterface()) {
return (T) InterfaceProxy.newInstance(innerClass);
} else {
// 返回基于CGLIB的动态代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(innerClass);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallback(new MethodInterceptorImpl());
return (T) enhancer.create();
}
}

// 返回实际的被代理对象类型,当调用getBean(xxx.class)时进行类型匹配
public Class<?> getObjectType() {
try {
return Class.forName(proxyClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

// 默认是单例
public boolean isSingleton() {
return true;
}

}

public static class InterfaceProxy implements InvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("ObjectProxy execute:" + method.getName());
return method.invoke(proxy, args);
}

public static <T> T newInstance(Class<T> innerInterface) {
ClassLoader classLoader = innerInterface.getClassLoader();
Class[] interfaces = new Class[]{innerInterface};
InterfaceProxy proxy = new InterfaceProxy();
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}

}

public static class MethodInterceptorImpl implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws
Throwable {
System.out.println("MethodInterceptorImpl:" + method.getName());
return methodProxy.invokeSuper(o, objects);
}

}

测试用例

public static void main(String[] args) {
// 创建IOC容器上下文
GenericApplicationContext context = new GenericApplicationContext();

// 定义GenericBeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.getPropertyValues().add("proxyClassName", PrintClass.class.getName());
beanDefinition.setBeanClass(ProxyFactoryBean.class);

// 向容器注入Bean并刷新上下文
context.registerBeanDefinition("printClassBean", beanDefinition);
context.refresh();

// 从容器中获取代理proxyBean
PrintClass proxyBean = context.getBean(PrintClass.class);

// 执行代理Bean的方法
proxyBean.print();
}

public static class PrintClass {
public void print() {
System.out.println("PrintClass");
}
}

输出结果:

MethodInterceptorImpl:print
PrintClass

实现原理分析

核心类:AbstractBeanFactory 继承自 FactoryBeanRegistrySupport。当从IOC容器中调用getBean方法时,底层会调用AbstractBeanFactory的getObjectForBeanInstance方法,如果当前BeanDefinition关联的beanClass为FactoryBean类型则调用其getObject方法,如果是普通类型则直接返回该实例。

AbstractBeanFactory 类:

/**
* Get the object for the given bean instance, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param beanInstance the shared bean instance
* @param name name that may include factory dereference prefix
* @param beanName the canonical bean name
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}

// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 关键之处:如果是普通的bean则直接返回,如果是FactoryBean则继续向下走
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}

Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

@Override
public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);

// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
if (beanInstance instanceof FactoryBean) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是FactoryBean则获取实际被代理的Class类型
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isInstance(beanInstance);
}
}
else if (!BeanFactoryUtils.isFactoryDereference(name)) {
if (typeToMatch.isInstance(beanInstance)) {
// Direct match for exposed instance?
return true;
}
.....
.........
............
}
}

FactoryBeanRegistrySupport类:


/**
* Obtain an object to expose from the given FactoryBean.
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {

Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
// 调用factory的getObject()方法生成动态代理类
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// 调用factory的getObject()方法生成动态代理类
object = factory.getObject();
}
} catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}

// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}

/**
* Determine the type for the given FactoryBean.
* @param factoryBean the FactoryBean instance to check
* @return the FactoryBean's object type,
* or {@code null} if the type cannot be determined yet
*/
protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
try {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
@Override
public Class<?> run() {
// 返回被代理类的Class类型
return factoryBean.getObjectType();
}
}, getAccessControlContext());
}
else {
// 返回被代理类的Class类型
return factoryBean.getObjectType();
}
}
catch (Throwable ex) {
// Thrown from the FactoryBean's getObjectType implementation.
logger.warn("FactoryBean threw exception from getObjectType, despite the contract saying " +
"that it should return null if the type of its object cannot be determined yet", ex);
return null;
}
}